package view.GUI.adminView.charts;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.controlsfx.control.CheckComboBox;
import org.controlsfx.control.IndexedCheckModel;
import org.controlsfx.dialog.Dialogs;

import model.Configuration;
import model.data.interfaces.IFinishable;
import model.data.tableModel.person.Customer;
import view.GUI.mainView.MainView;
import enums.GUIText;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.ToggleButton;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.stage.Stage;

public final class RevenueChart extends Application {

	private GridPane root;
	private CategoryAxis xAxis;
	private NumberAxis yAxis;
	private Separator sepTop;
	private Separator sepBottom;
	private Label lblTitle;
	
	private LineChart<String, Number> lineChart;
	private Stage primaryStage;
	private Scene scene;
	private MainView owner;
	
	private CheckComboBox<IFinishable> cmbCustomer;
	private ToggleButton tglRevenue;
	private ToggleButton tglProfit;
	private int rowCounter;
	private DatePicker beginDatePicker;
	private DatePicker endDatePicker;
	private Label lblBeginDate;
	private Label lblEndDate;
	private Label lblCustomer;
		
	public RevenueChart(MainView instance){
		this.rowCounter = 1;
		this.owner = instance;
		createWidgets();
		addWidgets();
		setupLayout();
		setupInteraction();
		setupData();
		
		start(new Stage());
	}
	
	/**
	 * Sets up the data that is shown by the chart.
	 */
	private void setupData() {
		lineChart.getData().clear();
		if(tglRevenue.isSelected()){
			setupChartData(true);			
		}
		if(tglProfit.isSelected()){
			setupChartData(false);
		}
	}


	/**
	 * Sets up the series for the line chart;
	 * @param isRevenue Select true if the revenue series should be added or false if the profit series should be added
	 */
	private void setupChartData(boolean isRevenue) {
		List<XYChart.Series<String, Number>> revenueSeries = new ArrayList<>();
		List<IFinishable> selectedCustomer = cmbCustomer.getCheckModel().getCheckedItems();
		lineChart.autosize();
		// Draw one line for all customer
		if(selectedCustomer.isEmpty()){
			XYChart.Series<String, Number> series = getSeries(isRevenue, selectedCustomer);
			revenueSeries.add(series);
			if(isRevenue){
				series.setName(GUIText.REVENUE.toString() + " Gesamt");
			} else{
				series.setName(GUIText.PROFIT.toString() + " Gesamt");
			}
		} else{
			// Draw a line for each customer
			for(IFinishable i: selectedCustomer){
				ArrayList<IFinishable> selectedSingleCustomer = new ArrayList<IFinishable>();
				selectedSingleCustomer.add(i);
				XYChart.Series<String, Number> series = getSeries(isRevenue, selectedSingleCustomer);
				if(isRevenue){
					series.setName(GUIText.REVENUE.toString() + " " + ((Customer) i).getName());
				} else{
					series.setName(GUIText.PROFIT.toString() + " " + ((Customer) i).getName());
				}				
				revenueSeries.add(series);
			}
		}
		
		for(XYChart.Series<String, Number> series: revenueSeries){
			lineChart.getData().add(series);			
		}
	}

	/**
	 * 
	 * @param isRevenue true if a revenueSeries should be returned, false if a profit series should be returned
	 * @param selectedCustomer List of customer that are selected
	 * @return A Series containing values for the invoked information of the specific customers
	 */
	private XYChart.Series<String, Number> getSeries(boolean isRevenue, List<IFinishable> selectedCustomer) {
		XYChart.Series<String, Number> series = new XYChart.Series<>();
		Map<String, Number> data = owner.getChartData(isRevenue, selectedCustomer, beginDatePicker.getValue(), endDatePicker.getValue());
		for(String s: data.keySet()){
			Number nmb = data.get(s);
			series.getData().add(new XYChart.Data<>(s,nmb));
		}
		return series;
	}

	private void createWidgets() {
		lblCustomer = new Label(GUIText.CUSTOMER.toString());
		lblTitle = new Label(GUIText.VERLAUF.toString());
		sepTop = new Separator();
		sepBottom = new Separator();
		xAxis = new CategoryAxis();
		yAxis = new NumberAxis();
		lineChart = new LineChart<>(xAxis, yAxis);
		root = new GridPane();
		cmbCustomer = new CheckComboBox<>();
		cmbCustomer.getItems().addAll(owner.getActiveCustomer());
		tglRevenue = new ToggleButton(GUIText.REVENUE.toString());
		tglProfit = new ToggleButton(GUIText.PROFIT.toString());
		endDatePicker = new DatePicker();
		beginDatePicker = new DatePicker();
		lblBeginDate = new Label(GUIText.BEGIN.toString());
		lblEndDate = new Label(GUIText.END.toString());
	}

	private void addWidgets() {
		root.add(lblTitle, 0, rowCounter++);
		root.add(sepTop, 0, rowCounter++);
		root.add(lblCustomer, 0, rowCounter);
		root.add(lblBeginDate, 3, rowCounter);
		root.add(lblEndDate, 4, rowCounter++);
		root.add(cmbCustomer, 0, rowCounter);
		root.add(tglRevenue, 1, rowCounter);
		root.add(tglProfit, 2, rowCounter);
		root.add(beginDatePicker, 3, rowCounter);
		root.add(endDatePicker, 4, rowCounter++);
		root.add(lineChart, 0, rowCounter++);
		root.add(sepBottom, 0, rowCounter++);
		
	}

	private void setupLayout() {
		GridPane.setColumnSpan(sepTop, 8);
		GridPane.setColumnSpan(sepBottom, 8);
		GridPane.setColumnSpan(lineChart, 8);
		tglProfit.setPrefWidth(125);
		tglRevenue.setPrefWidth(125);
		lblTitle.setId("topic");
		root.getStyleClass().add("grid");
		cmbCustomer.setMaxSize(225, 25);
		yAxis.setAutoRanging(true);
		xAxis.setAutoRanging(true);
		xAxis.setLabel(GUIText.MONTH.toString());
		beginDatePicker.setValue(LocalDate.of(LocalDate.now().getYear(), 1, 1));
		endDatePicker.setValue(LocalDate.now());
	}

	private void setupInteraction() {
		tglRevenue.setOnAction(new EventHandler<ActionEvent>(){

			@Override
			public void handle(ActionEvent arg0) {
				setupData();
			}
		});
		tglProfit.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent arg0) {
				setupData();
			}
		});
		cmbCustomer.checkModelProperty().addListener(new ChangeListener<IndexedCheckModel<IFinishable>>(){
			@Override
			public void changed(ObservableValue<? extends IndexedCheckModel<IFinishable>> observable, IndexedCheckModel<IFinishable> oldValue,
					IndexedCheckModel<IFinishable> newValue) {
				setupData();
			}
		});
		beginDatePicker.setOnAction(new EventHandler<ActionEvent>(){

			@Override
			public void handle(ActionEvent event) {
				setupData();
			}
		});
		endDatePicker.setOnAction(new EventHandler<ActionEvent>(){

			@Override
			public void handle(ActionEvent event) {
				setupData();
			}
		});
	}
	
	
	private void saveChart(){
		WritableImage snapShot = scene.snapshot(null);

        try {
			ImageIO.write(SwingFXUtils.fromFXImage(snapShot, null), "png", new File("image.png"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void start(Stage stage) {
		stage.setTitle(GUIText.REVENUE.toString());
		this.primaryStage = stage;
		this.scene = new Scene(root);
		scene.getStylesheets().add(getClass().getResource(Configuration.STYLECHART).toExternalForm());
		scene.getStylesheets().add(getClass().getResource(Configuration.STYLEROOT).toExternalForm());
		this.primaryStage.initModality(Modality.WINDOW_MODAL);
		stage.initOwner(owner.getPrimaryStage());
		stage.setScene(scene);
		primaryStage.centerOnScreen();
		stage.show();
		scene.setOnMousePressed(new EventHandler<MouseEvent>(){
			
			@Override
			public void handle(MouseEvent event) {
				if(event.isSecondaryButtonDown()){
					saveChart();
					Dialogs.create()
					.message("Image saved")
					.showInformation();
				}
			}
		});
	}
}
